package istar.agent;

import istar.IActor;
import istar.IDependency;
import istar.IElement;
import istar.IElementLink;
import istar.IGoal;
import istar.IPosition;
import istar.IRole;
import istar.ISoftgoal;
import istar.ITask;
import istar.impl.AbstractBasicBelief;
import istar.impl.AbstractBasicGoal;
import istar.impl.AbstractBasicResource;
import istar.impl.AbstractBasicSoftgoal;
import istar.impl.AbstractBasicTask;
import istar.impl.AbstractMainGoal;
import istar.impl.Actor;
import istar.impl.Belief;
import istar.impl.ContributionLink;
import istar.impl.Dependency;
import istar.impl.EvaluationLink;
import istar.impl.Goal;
import istar.impl.IstarAgent;
import istar.impl.MeansEndLink;
import istar.impl.Position;
import istar.impl.Resource;
import istar.impl.Role;
import istar.impl.Softgoal;
import istar.impl.Task;
import istar.impl.TaskDecompositionLink;
import jade.core.Agent;
import jade.core.Runtime;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import fexception.IJFException;



public class IstarModelLoader {

	/**
	 * @param args
	 */
	private static IstarModelLoader instance;

	private HashMap<String, IElement> externalElements = new HashMap<String, IElement>();
	private HashMap<String, IActor> actors = new HashMap<String, IActor>();
	private Agent loader;
	private String logFilePath = "";
	private String configPath = "";
	
    public static IstarModelLoader getInstance(String _pathToConfigFile, Agent agent)
    {
    	if (instance == null)
    		instance = new IstarModelLoader(_pathToConfigFile,agent);
        return instance;
    }
    
	private IstarModelLoader(String _pathToConfigFile, Agent agent) {
		String _pathToIstarMLFile = null;
		configPath = _pathToConfigFile;
		try {
			BufferedReader in = new BufferedReader(new FileReader(configPath));
		    String str;
		    while ((str = in.readLine()) != null) {
		        if (str.startsWith("ModelFile=")){
		        	_pathToIstarMLFile = str.substring(10);
		        }
		        if (str.startsWith("LogFile=")){
		        	logFilePath = str.substring(8);
		        }
		    }
		    in.close();

			loader = agent;
			//logFilePath = _pathToLogFile;
			loadIstarMLModel(_pathToIstarMLFile);
			//test();
			initialize();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void loadIstarMLModel(String _pathToFile) throws Exception {
		File istarMLFile;
		try {
			istarMLFile = new File(_pathToFile);
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(istarMLFile);
			doc.getDocumentElement().normalize();
			
			NodeList ndListFile= doc.getDocumentElement().getChildNodes();
			for (int i = 0; i < ndListFile.getLength(); i++) {
				Node ndFile = ndListFile.item(i);
				if (ndFile.getNodeType() == Node.ELEMENT_NODE) {
					NodeList ndLst = ndFile.getChildNodes();
					for (int j = 0; j < ndLst.getLength(); j++) {
						Node elmntNode = ndLst.item(j);
						if (elmntNode.getNodeType() == Node.ELEMENT_NODE) {
							Element elmnt = (Element)elmntNode;
							String elementType = elmnt.getTagName();
							if (elementType.equals("actor")){
								loadActor(elmnt);
							}
						}
					}
					for (int m = 0; m < ndLst.getLength(); m++) {
						Node elmntNode = ndLst.item(m);
						if (elmntNode.getNodeType() == Node.ELEMENT_NODE) {
							Element elmnt = (Element)elmntNode;
							if (elmnt.getTagName().equals("ielement")){
								loadExternalElements(elmnt);
							}
						}
					}
				}
			}
			
			for (int i = 0; i < ndListFile.getLength(); i++) {
				Node ndFile = ndListFile.item(i);
				if (ndFile.getNodeType() == Node.ELEMENT_NODE) {
					NodeList ndLst = ndFile.getChildNodes();
					for (int j = 0; j < ndLst.getLength(); j++) {
						Node elmntNode = ndLst.item(j);
						if (elmntNode.getNodeType() == Node.ELEMENT_NODE) {
							Element elmnt = (Element)elmntNode;
							String elementType = elmnt.getTagName();
							if (elementType.equals("actor")){
								loadActorElementLinks(elmnt);
							}
						}
					}
				}
			}
		} 
		catch (Exception e) {
			e.printStackTrace();
		}

	}
	
    private void loadActor(Element elmnt) throws Exception{
    	IActor actor = null;
		if (elmnt.getAttribute("type").equals("role")){
			actor = new Role(elmnt.getAttribute("name"));
		} else if (elmnt.getAttribute("type")==null){
			actor = new Actor(elmnt.getAttribute("name"));
		} else if (elmnt.getAttribute("type").equals("agent")){
			actor = new IstarAgent(elmnt.getAttribute("name"));
		} else if (elmnt.getAttribute("type").equals("position")){
			actor = new Position(elmnt.getAttribute("name"));
		}
		actors.put(elmnt.getAttribute("id"), actor);
		
		if (actor!=null){
			actor.setId(elmnt.getAttribute("id"));
			NodeList internalList = elmnt.getChildNodes();
			for (int k=0; k<internalList.getLength();k++){
				Node internalNode = internalList.item(k);
				if (internalNode.getNodeType() == Node.ELEMENT_NODE){
					Element internalElmntNode = (Element)internalNode;
					loadInternalElement(internalElmntNode, actor);
				}
			}
		}
    }

    private void loadExternalElements(Element elmnt) throws Exception {
    	IElement extIElmnt = null;

    	if (elmnt.getAttribute("type").equals("task")){
			Task extTask = new Task(elmnt.getAttribute("name"));
			extTask.setId(elmnt.getAttribute("id"));
			if (!elmnt.getAttribute("cost").equals("")){
				extTask.setCost(new Double(elmnt.getAttribute("cost")));
			}
			extIElmnt = extTask;
		} else if (elmnt.getAttribute("type").equals("resource")){
			 Resource extResource = new Resource(elmnt.getAttribute("name"));
			 extResource.setId(elmnt.getAttribute("id"));
			 extIElmnt = extResource;
		} else if (elmnt.getAttribute("type").equals("goal")){
			Goal extGoal = new Goal(elmnt.getAttribute("name"));
			extGoal.setId(elmnt.getAttribute("id"));
			extIElmnt = extGoal;
		} else if (elmnt.getAttribute("type").equals("softgoal")){
			Softgoal extSoftgoal = new Softgoal(elmnt.getAttribute("name"));
			extSoftgoal.setId(elmnt.getAttribute("id"));
			extIElmnt = extSoftgoal;
		} else if (elmnt.getAttribute("type").equals("belief")){
			IElement topic = null;
			Iterator<IActor> itActors = actors.values().iterator();
			while (itActors.hasNext()){
				IActor act = itActors.next();
				if (topic==null && elmnt.getAttribute("topicref")!=""){
					topic = act.getInternalElement(elmnt.getAttribute("topicref"));
				}
			}
			//if (topic!=null){
				Belief belief = new Belief(elmnt.getAttribute("name"), topic);
				belief.setId(elmnt.getAttribute("id"));
				extIElmnt = belief;
			//}

		} 
		/*
		else if (elmnt.getAttribute("type").equals("knowledge")){
			IElement topic = null;
			Iterator<IActor> itActors = actors.values().iterator();
			while (itActors.hasNext()){
				IActor act = itActors.next();
				if (topic==null && elmnt.getAttribute("topicref")!="")
					topic = act.getInternalElement(elmnt.getAttribute("topicref"));
			}
			if (topic!=null){
				Knowledge know = new Knowledge(elmnt.getAttribute("name"), topic);
				know.setId(elmnt.getAttribute("id"));
				extIElmnt = know;
			}
		}
		*/
		if (extIElmnt!=null){
			externalElements.put(extIElmnt.getId(), extIElmnt);
			NodeList depNodeList = elmnt.getChildNodes();
			for (int n = 0; n < depNodeList.getLength(); n++){
				Node depNode = depNodeList.item(n);
				if (depNode.getNodeType()==Node.ELEMENT_NODE) {
					Element elmntDep = (Element)depNode;
					if (elmntDep.getTagName().equals("dependency")){
						loadDependencies(elmntDep, extIElmnt);					
					}
					//
					if (elmntDep.getTagName().equals("ielementLink") && 
						elmntDep.getAttribute("type").equals("argumentation") &&
						extIElmnt.getClass().equals(Belief.class)){
						loadEvaluationLink(elmntDep, (Belief)extIElmnt);					
					}
					//
				}
			}
		}
    }

    private void loadInternalElement(Element internalElmntNode, IActor actor) throws Exception{
    	if (internalElmntNode.getTagName().equals("actorLink") && internalElmntNode.getAttribute("type").equals("plays") ){
			if (actor.getClass()!=IstarAgent.class){
				throw new Exception("Invalid element node play for actor type " + actor.getClass().getName());
			} 
			else {
				try {
					IActor act = actors.get(internalElmntNode.getAttribute("aref"));
					Role role = (Role)act;
					((IstarAgent)actor).getPlays().add(role);
				} catch (Exception e) {
					throw new Exception("Invalid reference for element node play " + internalElmntNode.getAttribute("aref"));
				}
			}
		} 
		else if (internalElmntNode.getTagName().equals("actorLink") && internalElmntNode.getAttribute("type").equals("occupies")){
			if (actor.getClass()!=IstarAgent.class){
				throw new Exception("Invalid element node occupy for actor type " + actor.getClass().getName());
			} 
			else {
				try {
					IActor act = actors.get(internalElmntNode.getAttribute("aref"));
					Position position = (Position)act;
					((IstarAgent)actor).getOccupies().add(position);
				} catch (Exception e) {
					throw new Exception("Invalid reference for element node occupy " + internalElmntNode.getAttribute("aref"));
				}
			}
		} 
		else if (internalElmntNode.getTagName().equals("actorLink") && internalElmntNode.getAttribute("type").equals("covers")){
			if (actor.getClass()!=Position.class){
				throw new Exception("Invalid element node cover for actor type " + actor.getClass().getName());
			} 
			else {
				try {
					IActor act = actors.get(internalElmntNode.getAttribute("aref"));
					Role role = (Role)act;
					((Position)actor).getCovers().add(role);
				} catch (Exception e) {
					throw new Exception("Invalid reference for element node cover " + internalElmntNode.getAttribute("aref"));
				}
			}
		} 
		else if (internalElmntNode.getTagName().equals("boundary")){ 
			NodeList subElmntsNode = internalElmntNode.getChildNodes();
			for (int l=0; l < subElmntsNode.getLength(); l++){
				Node actorElmntNode = subElmntsNode.item(l);
				if (actorElmntNode.getNodeType() == Node.ELEMENT_NODE){
					Element subElmntNode = (Element)actorElmntNode;
					if (subElmntNode.getTagName().equals("ielement")){
						loadInBoundaryElements(subElmntNode, actor);
					}
				}
			}
		}
    }

    private void loadInBoundaryElements(Element subElmntNode, IActor actor) throws Exception{
		IElement internalElmnt=null; 

		if (subElmntNode.getAttribute("basic").equals("true")){
			Class<?> elementClass;
			if ((subElmntNode.getAttribute("urlClass")!="")&&(subElmntNode.getAttribute("behaviourClass")!="")){
				System.out.println("looking for: " + subElmntNode.getAttribute("behaviourClass"));
				URL[] urls = new URL[] { new URL(subElmntNode.getAttribute("urlClass")) };
				ClassLoader loader = new URLClassLoader(urls);
				elementClass = loader.loadClass(subElmntNode.getAttribute("behaviourClass"));
			}
			else
				elementClass  = getBasicClass(subElmntNode.getAttribute("name"));
			
			if (subElmntNode.getAttribute("type").equals("task")){
				try {
					internalElmnt = (AbstractBasicTask)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}
			
			if (subElmntNode.getAttribute("type").equals("resource")){
				try {
					//Class taskClass = getBasicClass(subElmntNode.getAttribute("name"));
					internalElmnt = (AbstractBasicResource)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}
			
			if (subElmntNode.getAttribute("type").equals("goal")){
				try {
					//Class taskClass = getBasicClass(subElmntNode.getAttribute("name"));
					internalElmnt = (AbstractBasicGoal)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}

			if (subElmntNode.getAttribute("type").equals("softgoal")){
				try {
					//Class taskClass = getBasicClass(subElmntNode.getAttribute("name"));
					internalElmnt = (AbstractBasicSoftgoal)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}
			
			/*
			if (subElmntNode.getAttribute("type").equals("knowledge")){
				try {
					//Class taskClass = getBasicClass(subElmntNode.getAttribute("name"));
					internalElmnt = (AbstractBasicSoftgoal)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}
			*/
			if (subElmntNode.getAttribute("type").equals("belief")){
				try {
					//Class taskClass = getBasicClass(subElmntNode.getAttribute("name"));
					internalElmnt = (AbstractBasicBelief)elementClass.newInstance();
				} catch (Exception e) {
					throw e;
				}
			}
		}
		else {
			if (subElmntNode.getAttribute("type").equals("resource")){
				internalElmnt = new Resource(subElmntNode.getAttribute("name"), actor);
			}
			if (subElmntNode.getAttribute("type").equals("task")){
				internalElmnt = new Task(subElmntNode.getAttribute("name"), actor);
			}
			if (subElmntNode.getAttribute("type").equals("goal")){
				if (subElmntNode.getAttribute("main").equals("true")) {
					
					//
					if ((subElmntNode.getAttribute("urlClass")!="")&&(subElmntNode.getAttribute("behaviourClass")!="")){
						System.out.println("looking for: " + subElmntNode.getAttribute("behaviourClass"));
						URL[] urls = new URL[] { new URL(subElmntNode.getAttribute("urlClass")) };
						ClassLoader loader = new URLClassLoader(urls);
						Class<?> goalClass = loader.loadClass(subElmntNode.getAttribute("behaviourClass"));
						internalElmnt = (AbstractMainGoal)goalClass.newInstance();
					}
					else {
						internalElmnt = (AbstractMainGoal)getMainGoalClass(subElmntNode.getAttribute("name")).newInstance();
					}

				}
				else
					internalElmnt = new Goal(subElmntNode.getAttribute("name"), actor);
			}
			if (subElmntNode.getAttribute("type").equals("softgoal")){
				internalElmnt = new Softgoal(subElmntNode.getAttribute("name"), actor);			
			}
			/*
			if (subElmntNode.getAttribute("type").equals("knowledge")){
				internalElmnt = new Knowledge(subElmntNode.getAttribute("name"), actor);			
			}
			*/
			if (subElmntNode.getAttribute("type").equals("belief")){
				internalElmnt = new Belief(subElmntNode.getAttribute("name"), actor);			
			}
			
		}
		
		if (subElmntNode.getAttribute("type").equals("goal")){
			if (subElmntNode.getAttribute("goaltype").equals("achive")){
				((Goal)internalElmnt).setGoalType(IGoal.ACHIEVE);
			}
			else if (subElmntNode.getAttribute("goaltype").equals("mantain")){
				((Goal)internalElmnt).setGoalType(IGoal.MANTAIN);
			}
			else if (subElmntNode.getAttribute("goaltype").equals("perform")){
				((Goal)internalElmnt).setGoalType(IGoal.PERFORM);
			}
		}
		
		/*
		if (subElmntNode.getAttribute("type").equals("belief")){
			IElement topic = null;
			Iterator<IActor> itActors = actors.values().iterator();
			while (itActors.hasNext()){
				IActor act = itActors.next();
				if (topic==null)
					topic = act.getInternalElement(subElmntNode.getAttribute("topicref"));
			}
			if (topic!=null){
				((Belief)internalElmnt).setElement(topic);
			}
			else System.out.println("Belief" + subElmntNode.getAttribute("name") + ": Topic not found");
		}
		
		if (subElmntNode.getAttribute("type").equals("knowledge")){
			IElement topic = null;
			Iterator<IActor> itActors = actors.values().iterator();
			while (itActors.hasNext()){
				IActor act = itActors.next();
				if (topic==null)
					topic = act.getInternalElement(subElmntNode.getAttribute("topicref"));
			}
			if (topic!=null){
				((Knowledge)internalElmnt).setElement(topic);
			}
			else System.out.println("Knowledge" + subElmntNode.getAttribute("name") + ": Topic not found");
		}
		*/

		if (internalElmnt!=null){
			internalElmnt.setId(subElmntNode.getAttribute("id"));
			internalElmnt.setOwner(actor);		}
		
	}
    
    
    private void loadEvaluationLink(Element elmntDep, Belief belief) throws Exception {
    	NodeList depActorsList = elmntDep.getChildNodes();
		
    	for (int o=0; o < depActorsList.getLength();o++){
			Node depActor = depActorsList.item(o);
			if (depActor.getNodeType()==Node.ELEMENT_NODE){
				Element elmntDepActor = (Element)depActor;
				String targetGoalId=null;
				if (elmntDepActor.getTagName().equals("ielement")){
					if (!elmntDepActor.getAttribute("iref").equals("")){
						targetGoalId = elmntDepActor.getAttribute("iref");
						Iterator<IActor> itActors = actors.values().iterator();
						while (itActors.hasNext()){
							IActor act = itActors.next();
							Iterator<IElement> intElmnts = act.getInboundaryElements().iterator();
							while (intElmnts.hasNext()){
								IElement intElmnt = intElmnts.next();
								if (intElmnt.getId().equals(targetGoalId)){
									EvaluationLink evalLink = new EvaluationLink("eval-"+intElmnt.getName(), 0, belief, intElmnt);
								}
							}
						}
					}
				}
			}
		}
    }

    
    private void loadDependencies(Element elmntDep, IElement extIElmnt) throws Exception {
    	NodeList depActorsList = elmntDep.getChildNodes();
		IActor depender =null, dependee=null;
		IElement dependeeElmnt=null, dependerElmnt=null;

		for (int o=0; o < depActorsList.getLength();o++){
			Node depActor = depActorsList.item(o);
			if (depActor.getNodeType()==Node.ELEMENT_NODE){
				Element elmntDepActor = (Element)depActor;
				String actorId = null, elmntId=null;
				if (elmntDepActor.getTagName().equals("depender")){
					if (!elmntDepActor.getAttribute("aref").equals("")){
						actorId = elmntDepActor.getAttribute("aref");
						depender =  actors.get(actorId);
					} 
					else {
						if (!elmntDepActor.getAttribute("iref").equals("")){
							elmntId = elmntDepActor.getAttribute("iref");
							Iterator<IActor> itActors = actors.values().iterator();
							while (itActors.hasNext()){
								IActor act = itActors.next();
								if (dependerElmnt==null)
									dependerElmnt = act.getInternalElement(elmntId);
							}
						}
					}
				} else if (elmntDepActor.getTagName().equals("dependee")){
					if (!elmntDepActor.getAttribute("aref").equals("")){
						actorId = elmntDepActor.getAttribute("aref");
						dependee =  actors.get(actorId);
					} 
					else {
						if (!elmntDepActor.getAttribute("iref").equals(""))
							elmntId = elmntDepActor.getAttribute("iref");
						Iterator<IActor> itActors = actors.values().iterator();
						while (itActors.hasNext()){
							IActor act = itActors.next();
							if (dependeeElmnt==null)
							dependeeElmnt = act.getInternalElement(elmntId);
						}
					}
				}
			}
		}
		
		if (depender!=null){
			if (dependee!=null){
				new Dependency(depender.getName() + "-" + extIElmnt.getName() + "-" + dependee.getName(), extIElmnt, depender, dependee);
			}
			else if (dependeeElmnt!=null){
				new Dependency(depender.getName() + "-" + extIElmnt.getName() + "-" + dependeeElmnt.getName(), extIElmnt, depender, dependeeElmnt);
			}
		} 
		else if (dependee!=null){
			new Dependency(dependerElmnt.getName() + "-" + extIElmnt.getName() + "-" + dependee.getName(), extIElmnt, dependerElmnt, dependee);													
		}
		else if (dependerElmnt!=null && dependeeElmnt!=null){
				new Dependency(dependerElmnt.getName() + "-" + extIElmnt.getName() + "-" + dependeeElmnt.getName(), extIElmnt, dependerElmnt, dependeeElmnt);
		}

    }
    
    private void loadActorElementLinks(Element elmnt)throws Exception {
		IActor actor = actors.get(elmnt.getAttribute("id"));
		if (actor!=null){
	    	NodeList internalList = elmnt.getChildNodes();
			for (int k=0; k<internalList.getLength();k++){
				Node internalNode = internalList.item(k);
				if (internalNode.getNodeType() == Node.ELEMENT_NODE){
					Element internalElmntNode = (Element)internalNode;
					if (internalElmntNode.getTagName().equals("boundary")){
						NodeList linkNodeList = internalElmntNode.getChildNodes();
						for (int n = 0; n < linkNodeList.getLength(); n++){
							Node iBasicElmntNode =  linkNodeList.item(n);
							if (iBasicElmntNode.getNodeType() == Node.ELEMENT_NODE){
								Element iBasicElem = (Element)iBasicElmntNode;
								if (iBasicElem.getTagName().equals("ielement")){
									
									
									String idElmt = iBasicElem.getAttribute("id");
									IElement internalElmnt = actor.getInternalElement(idElmt);
									NodeList linkElmntNodeList = iBasicElem.getChildNodes();

									for (int m=0; m < linkElmntNodeList.getLength(); m++){
										Node linkNode = linkElmntNodeList.item(m);
										if (linkNode.getNodeType()==Node.ELEMENT_NODE) {
											Element elmntLink = (Element)linkNode;
											if (elmntLink.getTagName().equals("ielementLink")) {
												if (elmntLink.getAttribute("type").equals("argumentation") &&
														internalElmnt.getClass().equals(Belief.class)){
														loadEvaluationLink(elmntLink, (Belief)internalElmnt);
												}
												else
													loadElementLinks(elmntLink, internalElmnt);
													
											}
										}
							        }
								}
							}
						}
					}
				}
			}
		}
    }
    
    private void loadElementLinks(Element elmntLink, IElement internalElmnt)throws Exception {
    	IActor actor = internalElmnt.getOwner();
    	//Vector<IElement> targets = new Vector<IElement>();
		Vector<String> targetIDs =  new Vector<String>();
		if (elmntLink.getAttribute("iref")!=""){
			targetIDs.add(elmntLink.getAttribute("iref"));
		}
		else {
			NodeList linkNodeList = elmntLink.getChildNodes();
			for (int n = 0; n < linkNodeList.getLength(); n++){
				Node iElementNode =  linkNodeList.item(n);
				if (iElementNode.getNodeType() == Node.ELEMENT_NODE){
					Element iElement = (Element)iElementNode;
					if (iElement.getTagName().equals("ielement")){
						targetIDs.add(iElement.getAttribute("iref"));
					}
				}
			}
		}

		Iterator<String> itTargetIDs = targetIDs.iterator();
		while (itTargetIDs.hasNext()){
			String targetID = itTargetIDs.next();
			IElement target = null;
			
			target = externalElements.get(targetID);
			if (target==null){
				target = actor.getInternalElement(targetID);
			}
			if (target==null)
				throw new Exception("Invalid target:" + targetID);
			
			if (elmntLink.getAttribute("type").equals("means-end")){
				try {
					ITask mean = (ITask)target;
					if (internalElmnt.getMeansEndLink()==null){
						new MeansEndLink(internalElmnt.getName(), internalElmnt, mean);
						if (elmntLink.getAttribute("run-mode").equals("parallel"))
							internalElmnt.getMeansEndLink().setType(IElementLink.PARALLEL);
						if (elmntLink.getAttribute("run-mode").equals("unique"))
							internalElmnt.getMeansEndLink().setType(IElementLink.UNIQUE);
					}
					else {
						internalElmnt.getMeansEndLink().getTargetElements().add(mean);
					}
				} catch (Exception e) {
					throw new Exception("Wrong mean element type! It must be a ITask and is " + target.getClass().getName());
				}
			}

			if (elmntLink.getAttribute("type").equals("decomposition")){
				try {
					ITask task = (ITask)internalElmnt;
					if (((ITask)internalElmnt).getMyDecompositionLink()==null){
						new TaskDecompositionLink(task, internalElmnt.getName(), target);
						if (elmntLink.getAttribute("run-mode").equals("parallel"))
							task.getMyDecompositionLink().setType(IElementLink.PARALLEL);
						if (elmntLink.getAttribute("run-mode").equals("sequential"))
							task.getMyDecompositionLink().setType(IElementLink.SEQUENTIAL);

					}
					else {
						((ITask)internalElmnt).getMyDecompositionLink().getTargetElements().add(target);
					}
				} catch (Exception e) {
					throw new Exception("Invalid link type! Taskdecomposition is not alowed for " + target.getClass().getName() + " only for ITask");
				}
			}

			if (elmntLink.getAttribute("type").equals("contribution")){
				ContributionLink contributionLink = null;
				try {
					if (internalElmnt.getClass().equals(Task.class)){
						contributionLink = new ContributionLink(internalElmnt.getName()+"-"+target.getName(), 
											 (ISoftgoal)target, (ITask)internalElmnt);
					}
					else if (internalElmnt.getClass().equals(Softgoal.class)){
						contributionLink = new ContributionLink(internalElmnt.getName()+"-"+target.getName(), 
								 (ISoftgoal)target, (ISoftgoal)internalElmnt);
					}
					else
						throw new Exception();
					
					String value = elmntLink.getAttribute("value");
					
					if (value.equals("++")){
						contributionLink.setValue(ContributionLink.DOUBLE_POSITIVE);
					}
					else if (value.equals("+")){
						contributionLink.setValue(ContributionLink.POSITIVE);
					}
					else if (value.equals("?")){
						contributionLink.setValue(ContributionLink.NEUTRAL);
					}
					else if (value.equals("-")){
						contributionLink.setValue(ContributionLink.NEGATIVE);
					}
					else if (value.equals("--")){
						contributionLink.setValue(ContributionLink.DOUBLE_NEGATIVE);
					}
				} catch (Exception e) {
					throw new Exception("Invalid link type! ContributionLink is not alowed for " + target.getClass().getName() + " only for ISoftgoal");
				}
			}
		}
    }
	

	
	private void test(){
		Iterator<IActor> itActors = actors.values().iterator();

		while (itActors.hasNext()){
			IActor actor = itActors.next();
			System.out.println();
			System.out.println("Actor " + actor.getName() + " type: " + actor.getClass());
			if (actor.getClass()==IstarAgent.class){
				if (!((IstarAgent)actor).getPlays().isEmpty()){
					Iterator<IRole> itRoles = ((IstarAgent)actor).getPlays().iterator();
					while (itRoles.hasNext()){
						IRole role = itRoles.next();
						System.out.println("Actor "+ actor.getName() + " plays Role: "+ role.getName());
					}
				}
				if (!((IstarAgent)actor).getOccupies().isEmpty()){
					Iterator<IPosition> itPositions = ((IstarAgent)actor).getOccupies().iterator();
					while (itPositions.hasNext()){
						IPosition position = itPositions.next();
						System.out.println("Actor "+ actor.getName() + " occupies Position: "+ position.getName());
					}
				}
				
			}
			Iterator<IElement> itIntElements = actor.getInboundaryElements().iterator();

			
			while (itIntElements.hasNext()){
				IElement intElmnt = itIntElements.next();
				if (intElmnt.isMain())
					System.out.println(actor.getName()+ " *** MAIN ELEMENT **** " + intElmnt.getId() + " name:" + intElmnt.getName() + " type:" + intElmnt.getClass());
				else
					System.out.println(actor.getName()+ " Internal ielement:" + intElmnt.getId() + " name:" + intElmnt.getName() + " type:" + intElmnt.getClass());
				if (intElmnt.getMeansEndLink()!=null){
					System.out.println(intElmnt.getName() + " Means-End link: " + intElmnt.getMeansEndLink().getType());
					Iterator<IElement> itMeans = intElmnt.getMeansEndLink().getTargetElements().iterator();
					while (itMeans.hasNext()){
						//MeansEndLink meansEndLink = itMeans.next();
						IElement mean = itMeans.next();
						System.out.println(" mean: type:" + mean.getClass() + 
											" id:" + mean.getId() + " name:" + mean.getName());
						
					}
				}
				if (intElmnt.getClass()==Task.class){
					if (((Task)intElmnt).getMyDecompositionLink()!=null){
						System.out.println(intElmnt.getName() + " TaskDecomposition link: " + ((Task)intElmnt).getMyDecompositionLink().getType());
						Iterator<IElement> itTaskDec = ((Task)intElmnt).getMyDecompositionLink().getTargetElements().iterator();
						while (itTaskDec.hasNext()){
							//TaskDecompositionLink taskDecLink = itTaskDec.next();
							IElement subElement = itTaskDec.next();
							System.out.println(" sub-element: type:" + subElement.getClass() +
									 " id:" + subElement.getId() + " name:" + subElement.getName());
							
						}
					}
				}
			}
			
			Iterator<IElement> itDependees = actor.getDependeeElements().iterator();
			while (itDependees.hasNext()){
				IElement dependum = itDependees.next();
				System.out.println(actor.getName() + " Dependee element: id:" + dependum.getId()  +
									" - dependum: type:" + dependum.getClass() + " name:" + dependum.getName());
				
			}
		}
		System.out.println("----//-----");
		
		Iterator<IElement> itElements = externalElements.values().iterator();

		while (itElements.hasNext()){
			IElement ielement = itElements.next();
			System.out.println();
			System.out.println("IBasicElement:" + ielement.getName() + " deps " +ielement.getDependencies().size());
			Iterator<IDependency> itDeps = ielement.getDependencies().iterator();
			while (itDeps.hasNext()){
				IDependency dep = itDeps.next();
				String sDepender, sDependee;
				if (dep.getDependeeElement()==null)
					sDependee = " dependee:" + dep.getDependee().getId();
				else 
					sDependee = " dependee:" + dep.getDependee().getId() + " dependee element:" + dep.getDependeeElement().getId();
			
				if (dep.getDependerElement()==null)
					sDepender = " depender:" + dep.getDepender().getId();
				else 
					sDepender = " depender:" + dep.getDepender().getId() + " depender element:" + dep.getDependerElement().getId();
				
				System.out.println("Dependency:" + dep.getName() + " type:" + dep.getClass() +
									sDepender + sDependee);
			}
		}
		System.out.println("------------");
	}
	
	//
	private Class<?> getBasicClass(String _className) throws ClassNotFoundException{
		String className = "basicelement."+  _className.substring(0,1).toUpperCase() +  _className.substring(1, _className.length());
		return Class.forName(className);
	}
	
	//
	private Class<?> getMainGoalClass(String _className) throws ClassNotFoundException{
		String className = "maingoal."+  _className.substring(0,1).toUpperCase() +  _className.substring(1, _className.length());
		return Class.forName(className);
	}
	
	private void initialize(){
		Vector<IActor> agents = new Vector<IActor>();
		Iterator<IActor> itActors = actors.values().iterator();
		while (itActors.hasNext()){
			IActor actor = itActors.next();
			if (actor.getClass().equals(IstarAgent.class) || actor.getClass().equals(Actor.class)){
				agents.add(actor);
			}
		}
		createJadeAgent(agents);
	}
	

	
	private void createJadeAgent(List<IActor> _actors){
		// Get a hold on JADE runtime
		Runtime rt = Runtime.instance();

		// Create a new jade agent
		// and pass it a reference to the _istarAgent
		for (int i=0;i<_actors.size();i++){
			Object agentArgs[] = new Object[2];
			IActor actor = _actors.get(i);
			agentArgs[0]=_actors.get(i);
			//agentArgs[1] = logFilePath;
			agentArgs[1] = configPath;
			String className;
			
			//if (actor.getName().equals("learner")){
			//	className = "RM.RapidLearner";
			//} 
			//else{
				className = "istar.agent.IstarJadeAgent";
			//}
				
			try {
				jade.core.Runtime runtime = jade.core.Runtime.instance();
				//runtime.setCloseVM(true);
				jade.wrapper.AgentContainer container = loader.getContainerController();
					//runtime.createAgentContainer(profile);
				
				container.start();   

				// Fire up the agent
				container.createNewAgent(actor.getName(),className, agentArgs).start();
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
		}
	}
	
	
}
